#!/usr/bin/env python

import argparse
import contextlib
import errno
import os
import shutil
import subprocess
import sys
import tempfile
import urllib2
import zipfile


SOURCE_ROOT = os.path.abspath(os.path.dirname(os.path.dirname(__file__)))

PLATFORM_KEY = {
  'cygwin': 'win',
  'darwin': 'osx',
  'linux2': 'linux',
  'win32': 'win',
}[sys.platform]

SHARED_LIBRARY_FILENAME = 'libchromiumcontent.zip'
STATIC_LIBRARY_FILENAME = 'libchromiumcontent-static.zip'


class ProgramError(Exception):
  pass


def main():
  try:
    args = parse_args()
    if (args.libcc_source_path != None and
        args.libcc_shared_library_path != None and
        args.libcc_static_library_path != None):
      if (not os.path.isdir(args.libcc_source_path)):
        print "Error: Directory does not exist:", args.libcc_source_path
        sys.exit(0)
      generate_filenames_gypi(os.path.join(args.path, 'filenames.gypi'),
                              args.libcc_source_path,
                              args.libcc_shared_library_path,
                              args.libcc_static_library_path)
    elif (args.libcc_source_path != None or
          args.libcc_shared_library_path != None or
          args.libcc_static_library_path != None):
      print "Error: All options of libchromiumcontent are required OR let libchromiumcontent choose it"
      sys.exit(0)
    else:
      if args.commit == 'HEAD':
        commit = head_commit()
      else:
        commit = args.commit
      if os.environ.has_key('MAS_BUILD'):
        platform = 'mas'
      else:
        platform = PLATFORM_KEY
      base_url = '{0}/{1}/{2}'.format(args.url, platform, args.target_arch)
      download_if_needed(args.path, base_url, commit, SHARED_LIBRARY_FILENAME,
                         args.force)
      if (args.static and
          not os.path.exists(os.path.join(args.path, 'static_library'))):
        download(args.path, base_url, commit, STATIC_LIBRARY_FILENAME)
      generate_filenames_gypi(os.path.join(args.path, 'filenames.gypi'),
                              os.path.join(args.path, 'src'),
                              os.path.join(args.path, 'shared_library'),
                              os.path.join(args.path, 'static_library'))
    with open(os.path.join(args.path, '.target_arch'), 'w') as f:
      f.write(args.target_arch)
  except ProgramError as e:
    return e.message


def parse_args():
  parser = argparse.ArgumentParser(description='Download and extract '
                                   'libchromiumcontent')
  parser.add_argument('-f', '--force', action='store_true',
                      help='Overwrite destination if it already exists.')
  parser.add_argument('-c', '--commit', nargs='?', default='HEAD',
                      help='The commit of libchromiumcontent to download.')
  parser.add_argument('-s', '--static', action='store_true',
                      help='Download static_library build')
  parser.add_argument('--target_arch', required=True,
                      help='The arch of libchromiumcontent to download.')
  parser.add_argument('url', help='The base URL from which to download '
                      '(i.e., the URL you passed to script/upload)')
  parser.add_argument('path', help='The path to extract to')
  parser.add_argument('--libcc_source_path', required=False,
                        help='The source path of libchromiumcontent. NOTE: All options of libchromiumcontent are required OR let libchromiumcontent choose it')
  parser.add_argument('--libcc_shared_library_path', required=False,
                        help='The shared library path of libchromiumcontent. NOTE: All options of libchromiumcontent are required OR let libchromiumcontent choose it')
  parser.add_argument('--libcc_static_library_path', required=False,
                        help='The static library path of libchromiumcontent. NOTE: All options of libchromiumcontent are required OR let libchromiumcontent choose it')
  return parser.parse_args()


def head_commit():
  cwd = os.getcwd()
  os.chdir(SOURCE_ROOT)
  try:
    args = ['git', 'rev-parse', 'HEAD']
    return subprocess.check_output(args).strip()
  finally:
    os.chdir(cwd)


def download_if_needed(destination, base_url, commit, filename, force):
  version_file = os.path.join(destination, '.version')
  existing_version = ''
  try:
    with open(version_file, 'r') as f:
      existing_version = f.readline().strip()
  except IOError as e:
    if e.errno != errno.ENOENT:
      raise
  if existing_version == commit:
    return

  if force:
    rm_rf(destination)
  elif os.path.exists(destination):
    raise ProgramError('Error: {0} already exists. Pass --force if you '
                       'want to overwrite it.'.format(destination))

  download(destination, base_url, commit, filename)

  with open(version_file, 'w') as f:
    f.write('{0}\n'.format(commit))


def download(destination, base_url, commit, filename):
  sys.stderr.write('Downloading {0}...\n'.format(filename))
  sys.stderr.flush()
  url = '{0}/{1}/{2}'.format(base_url, commit, filename)
  download_and_extract(destination, url)


def download_static_libraries(destination, base_url, commit):
  sys.stderr.write('Downloading static_library build of libchromiumcontent...')
  sys.stderr.flush()
  url = '{0}/{1}/libchromiumcontent-static.zip'.format(base_url, commit)
  download_and_extract(destination, url)


def download_and_extract(destination, url):
  print url
  with tempfile.TemporaryFile() as t:
    with contextlib.closing(urllib2.urlopen(url)) as u:
      while True:
        chunk = u.read(1024*1024)
        if not len(chunk):
          break
        sys.stderr.write('.')
        sys.stderr.flush()
        t.write(chunk)
    sys.stderr.write('\nExtracting...\n')
    sys.stderr.flush()
    with zipfile.ZipFile(t) as z:
      z.extractall(destination)


def generate_filenames_gypi(target_file, libcc_source_path,
                            libcc_shared_library_path,
                            libcc_static_library_path):
  generate = os.path.join(SOURCE_ROOT, 'tools', 'generate_filenames_gypi.py')
  subprocess.check_call([sys.executable, generate] + [target_file,
                         libcc_source_path, libcc_shared_library_path,
                         libcc_static_library_path])

def rm_rf(path):
  try:
    shutil.rmtree(path)
  except OSError as e:
    if e.errno != errno.ENOENT:
      raise


if __name__ == '__main__':
  sys.exit(main())
